package com.renne.ai.dbcmcp.service;

import com.renne.ai.dbcmcp.constant.Constants;
import com.renne.ai.dbcmcp.domain.SysTableColumnMeta;
import com.renne.ai.dbcmcp.domain.SysTableKeyColumnUsage;
import com.renne.ai.dbcmcp.domain.SysTableMeta;
import com.renne.ai.dbcmcp.domain.SysTableUniqueMeta;
import com.renne.ai.dbcmcp.mapper.DBQueryMapper;
import com.renne.ai.dbcmcp.properties.AppProperties;
import com.renne.ai.dbcmcp.utils.SpringUtils;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * 查询数据库表结构的服务
 *
 * @author LiuYu
 * @since 2025-03-31 19:01
 */
@Service
public class DBTableStructureService {

    @Resource
    private AppProperties appProperties;

    /**
     * 查询数据库所有表结构并返回表名和注释信息。
     * <p>
     * 该函数通过调用数据库查询接口，获取指定数据库中的所有表名及其注释信息，并将结果以字符串形式返回。
     *
     * @return 返回包含所有表名和注释信息的字符串，格式为列表的字符串表示形式。
     */
    @Tool(name = "getTableNameAndComment", description = """
            查询数据库所有表结构并返回表名和注释信息。
            该函数通过调用数据库查询接口，获取指定数据库中的所有表名及其注释信息，并将结果以字符串形式返回。
            返回包含所有表名和注释信息的字符串，格式为列表的字符串表示形式。
            """)
    public String getTableNameAndComment() {
        // 获取当前应用的数据库名称
        String dbType = appProperties.getDbType();
        String dbName = Objects.equals(dbType, Constants.DATABASE_TYPE_POSTGRESQL) ? appProperties.getSchemaName() :appProperties.getDbName();

        // 通过SpringUtils获取DBQueryMapper的实例，并调用其方法查询表名和注释信息
        List<SysTableMeta> tableNameAndComment = SpringUtils.getBean(DBQueryMapper.class).getTableNameAndComment(dbType, dbName);

        // 将查询结果转换为字符串并返回
        return tableNameAndComment.toString();
    }

    /**
     * 查询数据库表字段的详细信息。
     * <p>
     * 该函数通过指定的表名，查询数据库中该表的字段信息，并返回字段的元数据列表。
     *
     * @param tableName 表名，用于指定要查询的数据库表。
     * @return 返回包含表字段元数据的字符串表示形式。
     */
    @Tool(name = "getTableColumnDetail", description = """
            查询数据库表字段的详细信息。
            该函数通过指定的表名，查询数据库中该表的字段信息，并返回字段的元数据列表。
             返回包含表字段元数据的字符串表示形式。
            """)
    public String getTableColumnDetail(@ToolParam(description = "表名，用于指定要查询的数据库表。") String tableName) {
        // 获取当前应用的数据库名称
        String dbType = appProperties.getDbType();
        String dbName = Objects.equals(dbType, Constants.DATABASE_TYPE_POSTGRESQL) ? appProperties.getSchemaName() :appProperties.getDbName();

        // 通过DBQueryMapper查询指定表的字段元数据
        List<SysTableColumnMeta> tableNameAndComment = SpringUtils.getBean(DBQueryMapper.class).getTableColumnDetail(dbType, dbName, tableName);

        // 将字段元数据列表转换为字符串并返回
        return tableNameAndComment.toString();
    }

    /**
     * 查询指定数据库表的外键信息。
     * <p>
     * 该函数通过调用数据库查询接口，获取指定表的外键信息，并将其以字符串形式返回。
     *
     * @param tableName 需要查询外键信息的表名。
     * @return 返回包含外键信息的字符串，格式为列表的字符串表示。
     */
    @Tool(name = "getTableForeignKeys", description = """
            查询指定数据库表的外键信息。
            该函数通过调用数据库查询接口，获取指定表的外键信息，并将其以字符串形式返回。
            返回包含外键信息的字符串，格式为列表的字符串表示。
            """)
    public String getTableForeignKeys(@ToolParam(description = "需要查询外键信息的表名。") String tableName) {
        // 获取当前应用的数据库名称
        String dbType = appProperties.getDbType();
        String dbName = Objects.equals(dbType, Constants.DATABASE_TYPE_POSTGRESQL) ? appProperties.getSchemaName() :appProperties.getDbName();

        // 通过DBQueryMapper查询指定表的外键信息
        List<SysTableKeyColumnUsage> foreignKeys = SpringUtils.getBean(DBQueryMapper.class).getTableForeignKeys(dbType, dbName, tableName);

        // 将外键信息列表转换为字符串并返回
        return foreignKeys.toString();
    }

    /**
     * 查询指定表的索引信息。
     *
     * 该函数通过调用数据库查询接口，获取指定表的索引信息，并将结果以字符串形式返回。
     *
     * @param tableName 表名，用于指定需要查询索引信息的表。
     * @return 返回指定表的索引信息，以字符串形式表示。
     */
    @Tool(name = "getTableIndexes", description = """
            查询指定表的索引信息。
            该函数通过调用数据库查询接口，获取指定表的索引信息，并将结果以字符串形式返回。
            返回指定表的索引信息，以字符串形式表示。
            """)
    public String getTableIndexes(@ToolParam(description = "表名，用于指定需要查询索引信息的表。") String tableName) {
        // 获取当前应用的数据库名称
        String dbType = appProperties.getDbType();
        String dbName = Objects.equals(dbType, Constants.DATABASE_TYPE_POSTGRESQL) ? appProperties.getSchemaName() :appProperties.getDbName();


        // 调用数据库查询接口，获取指定表的索引信息
        List<SysTableUniqueMeta> indexes = SpringUtils.getBean(DBQueryMapper.class).getTableIndexes(dbType, dbName, tableName);

        // 将索引信息转换为字符串并返回
        return indexes.toString();
    }

    /**
     * 查询指定表的行数。
     *
     * 该函数通过调用数据库查询接口，获取指定表的行数，并返回包含行数的字符串信息。
     *
     * @param tableName 需要查询行数的表名，不能为空。
     * @return 返回一个字符串，格式为 "表 {tableName} 的行数为: {rowCount}"，其中 {tableName} 是传入的表名，{rowCount} 是查询到的行数。
     */
    @Tool(name = "getTableRowCount", description = """
            查询指定表的行数。
            该函数通过调用数据库查询接口，获取指定表的行数，并返回包含行数的字符串信息。
            返回一个字符串，格式为 "表 {tableName} 的行数为: {rowCount}"，其中 {tableName} 是传入的表名，{rowCount} 是查询到的行数。
            """)
    public String getTableRowCount(@ToolParam(description = "需要查询行数的表名。") String tableName) {

        String dbType = appProperties.getDbType();
        // 通过 SpringUtils 获取 DBQueryMapper 的实例，并调用其 getTableRowCount 方法查询表的行数
        int rowCount = SpringUtils.getBean(DBQueryMapper.class).getTableRowCount(dbType, tableName);

        // 返回包含表名和行数的字符串
        return "表 " + tableName + " 的行数为: " + rowCount;
    }

    /**
     * 查询数据库的存储引擎。
     *
     * 该函数通过应用程序配置获取数据库名称，并使用该名称查询数据库的存储引擎。
     * 最终返回一个包含数据库名称和存储引擎信息的字符串。
     *
     * @return 返回一个字符串，格式为 "数据库 [数据库名称] 的存储引擎为: [存储引擎]"
     */
    @Tool(name = "getDatabaseEngine", description = """
            查询数据库中指定表的存储引擎。
            该函数通过应用程序配置获取数据库名称，并使用该名称查询数据库的存储引擎，最终返回一个包含数据库名称和存储引擎信息的字符串。
            返回一个字符串，格式为 "数据库 [数据库名称] 中表 [表名称] 的存储引擎为: [存储引擎]"
            """)
    public String getDatabaseEngine(@ToolParam(description = "表名，用于指定需要查询存储引擎的表。") String tableName) {
        // 从应用程序配置中获取数据库名称
        String dbType = appProperties.getDbType();
        String dbName = Objects.equals(dbType, Constants.DATABASE_TYPE_POSTGRESQL) ? appProperties.getSchemaName() :appProperties.getDbName();

        // 通过Spring工具类获取DBQueryMapper的实例，并查询数据库的存储引擎
        String engine = SpringUtils.getBean(DBQueryMapper.class).getDatabaseEngine(dbType, dbName, tableName);

        // 返回包含数据库名称和存储引擎信息的字符串
        return "数据库 " + dbName + " 中表 " + tableName + " 的存储引擎为: " + engine;
    }
}
